home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / life.aqm / life.asm
Assembly Source File  |  1986-02-12  |  10KB  |  419 lines

  1. ;
  2. ; LIFE {from COMPUTE'S guide to machine language on the
  3. ;       IBM PC, an excellent introduction to assembler.
  4. ;                       Ed Dablin       }
  5. ;
  6.     page ,132
  7.     .sall
  8. ;
  9. ; This program plays the game of life.
  10. ; The user sets up the screen as he would like it to start
  11. ; and then presses <RETURN> and the program goes until
  12. ; he presses a key.
  13. ;
  14. ;
  15. UP_scan        equ 48h
  16. DOWN_scan    equ 50h
  17. LEFT_scan    equ 4bh
  18. RIGHT_scan    equ 4dh
  19. SPACE_scan    equ 39h
  20. RET_scan    equ 1ch
  21. ;
  22. cell        equ 15
  23. space        equ ' '
  24. normal        equ 7        ; normal attribute
  25. ;
  26. video        equ 10h        ; VIDEO I/O interrupt #
  27. DOS_func    equ 21h        ; DOS function call
  28. ;
  29. locate        macro row,column    ; set cursor position
  30.         mov ah,2
  31.         mov dh, row
  32.         mov dl,column
  33.         mov bh,0
  34.         int video
  35.         endm
  36. ;
  37. check    macro coord,value,offset    ;special macro for setup
  38.         local no_change
  39.         cmp coord,value
  40.         je no_change
  41.         add coord,offset
  42. no_change:    ret
  43.         endm
  44. ;
  45. output    macro character,attribute    ; puts character on screen
  46.         mov ah,10
  47.         mov bh,0
  48.         mov cx,1
  49.         mov al,character
  50.         int video
  51.         endm
  52. ;
  53. place    macro matrix,xpos,ypos,character    ; puts char in matrix
  54.         mov bx,ypos
  55.         shl bx,1
  56.         mov bx,row_addr[bx]
  57.         mov si,xpos
  58.         mov &matrix[bx+si],character
  59.         endm
  60. ;
  61. peek    macro matrix,xpos,ypos        ; look into matrix
  62.         mov bx,ypos
  63.         shl bx,1
  64.         mov bx,row_addr[bx]
  65.         mov si,xpos
  66.         mov al,&matrix[bx+si]
  67.         endm
  68. ;
  69. clear    macro matrix            ; clear matrix
  70.         mov cx,2000
  71.         mov al,space
  72.         lea di,es:matrix
  73.         rep stos matrix
  74.         endm
  75. ;
  76. data         segment
  77. matrix_1    db 2000 dup (?)
  78. matrix_2    db 2000 dup (?)
  79. ;
  80. population    dw ?            ; # cells
  81. generation    dw ?            ; # generations
  82. ;
  83. row_byte    equ this byte        ; row counter
  84. row_pos        dw ?
  85. col_byte    equ this byte        ; column counter
  86. col_pos        dw ?
  87. ;
  88. legal_keys    db UP_scan,DOWN_scan,LEFT_scan,RIGHT_scan
  89.         db SPACE_scan,RET_scan
  90. ;
  91. key_routines    dw do_up,do_down,do_left,do_right
  92.         dw era_cell,do_ret
  93. ;
  94.     ; ====== Title Messages ========
  95. title_mes    dw game,cr,cr,author,cr,date,cr,cr,key_mes,0h
  96. ;
  97. game        db 'The game of LIFE.$'
  98. cr        db 13,10,'$'        ; carriage ret/line feed
  99. author        db 'Implemented by Marc Sugiyama$'
  100. date        db 'September 12, 1984$'
  101. key_mes        db 'Press any key to continue:$'
  102. ins_mes        db 'Press any key to create a cell;'
  103.         db ' erase with space; start with return.$'
  104. gen_mes        db 'Generation:        '
  105.         db 'Population:$'
  106. again_mes    db 'Play LIFE again (y/n)? $'
  107. spaces        db 79 dup (' '),'$'
  108. ;
  109. row_addr    dw 0        ; table of 80s to find row address
  110.         irp row,<1,2,3,4,5,6>
  111.         dw &row*80
  112.         endm
  113.         irp row,<7,8,9,10,11,12>
  114.         dw &row*80
  115.         endm
  116.         irp row,<13,14,15,16,17,18>
  117.         dw &row*80
  118.         endm
  119. ;
  120. ; offsets for 8 directions
  121. direction    dw -81,-80,-79,-1,1,79,80,81
  122. data ends
  123. ;
  124. stack    segment stack
  125.         db 1024 dup (?)
  126. stack        ends
  127. ;
  128. code    segment
  129. program        proc far
  130.         assume es:data,ds:data,cs:code,ss:stack
  131.         push ds        ; for FAR return
  132.         mov ax,0
  133.         push ax
  134.         mov ax,data
  135.         mov ds,ax
  136.         mov es,ax
  137.         call do_title    ;print the title page
  138. ;
  139. runagain:    clear matrix_1    ;put spaces in matrices
  140.         clear matrix_2
  141.         mov population,0    ;zero population
  142.         mov generation,1    ;first generation
  143.         call do_setup        ;set up screen
  144.         jc done            ;if CF=1 then leave program
  145.         call play        ;play the scenario
  146.         call again        ;ask to play again
  147.         jc runagain        ;if CF=1 then play again
  148.         call cls        ;clear screen
  149. ;
  150. done:        ret
  151. program        endp
  152. ;
  153. ;Again asks if the player wants to play again. If so, CF
  154. ;is set. Otherwise, CF=0.
  155. ;All registers should be considered destroyed.
  156. ;
  157. again    proc near
  158.         locate 0,39        ;put cursor top line
  159.         mov dx, offset again_mes  ;set DS:DX to message
  160.         call print        ;print message
  161. check_key_again:
  162.         call press_key        ; get key press
  163.         and al,0dfh        ;'AND' out lower case bit
  164.         cmp al,'Y'
  165.         je playagain
  166.         cmp al,'N'        ;don't play again
  167.         jne check_key_again
  168. not_again:    clc            ;CF=0 means return to DOS
  169.         ret
  170. playagain:    stc            ;CF=1 means play again
  171.         ret
  172. again        endp
  173. ;
  174. ;Title clears the screen and prints the name of the program.
  175. ;Consider all registers destroyed.
  176. ;
  177. do_title    proc near
  178.         call cls        ;clear screen
  179.         locate 1,0        ;set cursor to print message
  180.         mov si,offset title_mes ;print messages one by one
  181. print_title:    mov dx,[si]        ;set DS:DX to message
  182.         cmp dx,0    ;if message offset is zero, then done
  183.         je wait_for_key
  184.         add si,2        ;point to next message
  185.         call print        ;print message
  186.         jmp print_title        ;get next message to print
  187. ;
  188. wait_for_key:    call press_key        ;wait for key press
  189.         ret            ;return to caller
  190. do_title    endp
  191. ;
  192. ;Set up the cells on the screen using user input.
  193. ;Consider all registers destroyed.
  194. ;
  195. do_setup    proc near
  196.         call cls
  197.         locate 0,0
  198.         mov dx,offset ins_mes
  199.         call print
  200. ;
  201.         mov row_pos,12        ;put cursor at center screen
  202.         mov col_pos,39
  203. ;
  204. poscrs:        locate row_byte,col_byte  ;set to center of screen
  205.         mov ah,0
  206.         int 16h            ;get keystroke
  207.         cmp ax,0        ;program interrupted
  208.         jne check_keys
  209.         stc            ;return with error
  210.         ret
  211. ;
  212. check_keys:    mov bx,0        ;check for which key
  213. checkloop:    cmp ah,legal_keys[bx]    ;if legal key, do routine
  214.         je do_key
  215.         inc bx
  216.         cmp byte ptr legal_keys[bx],0   ;last possible key?
  217.         jne checkloop
  218.         call set_cell        ;possible alternative
  219.         jmp poscrs
  220. ;
  221. do_key:        shl bx,1        ;2X for word table
  222.         call key_routines[bx]    ;call routine
  223.         jmp poscrs        ;do next key
  224. ;
  225. do_up:        check row_pos,1,-1
  226. do_down:    check row_pos,24,1
  227. do_left:    check col_pos,0,-1
  228. do_right:    check col_pos,79,1
  229.                     ;put new cell down
  230. set_cell:    peek matrix_2,col_pos,row_pos    ;check if cell there
  231.         cmp al,cell
  232.         je noset
  233.         output cell,normal    ;if new cell,put on screen
  234.         place matrix_2,col_pos,row_pos,cell  ;add to matrix
  235.         inc population
  236. noset:        ret            ;return to process next key
  237.                     ;remove cell from matrix
  238. era_cell:    peek matrix_2,col_pos,row_pos  ;check if cell there
  239.         cmp al,space
  240.         je noera
  241.         output space,normal    ;put space in spot
  242.         place matrix_2,col_pos,row_pos,space ;clear matrix spot
  243.         dec population
  244. noera:        ret            ;return to process next key
  245. do_ret:        pop ax
  246.         clc            ;continue with main program
  247.         ret            ;return to main level
  248. do_setup    endp
  249. ;
  250. ;Play, does the actual game, printing the generation at the
  251. ;top of the screen, as well as the number of cells living.
  252. ;Consider all registers destroyed.
  253. ;
  254. play    proc near
  255.         locate 0,0        ;clear frist row
  256.         mov dx,offset spaces
  257.         call print
  258.         locate 0,0        ;print counters at top
  259.         mov dx,offset gen_mes
  260.         call print        ;print ifo messages
  261. ;
  262.         cld            ;work up (sting ops)
  263. ;
  264. play_loop:    mov ah,1        ;pressing key interrupts play
  265.         int 16h
  266.         jz cont            ;if key pressed,stop
  267. stopplay:    ret
  268. cont:        call print_data        ;print gen and pop
  269.         cmp population,0    ;if no living cells,exit game
  270.         je stopplay
  271. ;
  272.         mov cx,2000        ;move matrix 2 to 1
  273.         lea si,ds:matrix_2
  274.         lea di,es:matrix_1
  275.         rep movs matrix_1,matrix_2
  276. ;
  277.         clear matrix_2
  278. ;
  279.         mov row_pos,1        ;start with row 1
  280. loop1:        mov col_pos,1        ;   and column 1
  281. loop2:        peek matrix_1,col_pos,row_pos
  282.         call look_around
  283.         cmp al,cell        ;check for cell (peek op)
  284.         jne nocell        ;jump if no cell
  285.         cmp cl,2        ;cell survives if surrounded by
  286.         je survive        ;2 or 3 other cells
  287.         cmp cl,3
  288.         je survive
  289.         locate row_byte,col_byte    ;set cursor pos
  290.         output space,normal        ;kill on screen
  291.         place matrix_2,col_pos,row_pos,space ;kill in matrix
  292.         dec population
  293.         jmp next
  294. ;
  295. survive:    place matrix_2,col_pos,row_pos,cell  ;put in matrix
  296.         jmp next
  297. ;
  298. nocell:        cmp cl,3        ;give birth of new cell
  299.         jne next
  300.         inc population
  301.         locate row_byte,col_byte
  302.         output cell,normal    ;make it bright
  303.         place matrix_2,col_pos,row_pos,cell  ;put in matrix
  304. ;
  305. next:        inc col_pos        ;do next column
  306.         cmp col_pos,79
  307.         jnb skip1        ;conditional jump too far
  308.         jmp loop2
  309. skip1:        inc row_pos        ;do next row
  310.         cmp row_pos,23        ;done all?
  311.         jnb skip2        ;short jump problem again
  312.         jmp loop1
  313. skip2:        inc generation
  314.         jmp play_loop
  315. play        endp
  316. ;
  317. ;Look_Around checks to see how many cells are around a
  318. ;space. Only BX,CX,DI,SI are used.
  319. ;
  320. look_around    proc near
  321.         mov bx,row_pos        ;find row
  322.         shl bx,1        ;get address from table of 80s
  323.         mov bx,row_addr[bx]
  324.         add bx,col_pos        ;add column to it
  325.         add bx,offset matrix_1    ;add offset into data seg
  326.         mov di,14        ;set DI to last dir offset
  327.         mov cl,8        ;set CL to all cells
  328. look_loop:    mov si,direction[di]    ;get direction offset
  329.         cmp byte ptr [bx][si],cell    ;see if cell
  330.         je look_next
  331.         dec cl            ;if not cell,reduce CL by 1
  332. look_next:    sub di,2        ;get next direction offset
  333.         jns look_loop        ;done them all?
  334.         ret            ;return to caller
  335. look_around    endp
  336. ;
  337. ;print_data outputs the population and the generation.
  338. ;Consider all registers lost;
  339. ;
  340. print_data    proc near
  341.         locate 0,11
  342.         mov ax,generation
  343.         call decimal_out
  344.         locate 0,30
  345.         mov ax,population
  346.         call decimal_out
  347.         ret
  348. print_data    endp
  349. ;
  350. ;Output a hex word in decimal.
  351. ;AX,DX,BP destroyed.
  352. ;
  353. decout        proc near
  354. tens        dw 1,10,100,1000,10000
  355. leading_zero    db 0            ;leading zero flag
  356. ;
  357. decimal_out:    mov leading_zero,1
  358.         mov bp,8        ;set BP to end of ten table
  359. ;
  360. decout1:    mov dx,0        ;prepare to divide
  361.         div tens[bp]        ;divide by power of ten
  362.         add al,'0'        ;convert to ascii
  363.         push dx            ;store remainder
  364.         cmp al,'0'        ;is byte a zero
  365.         jne send_char        ;no, so print it
  366.         cmp bp,0        ;Is it last character?
  367.         je send_char        ;yes, so print it
  368.         cmp leading_zero,1    ;Is it a leading zero?
  369.         je send_space        ;yes, so don't print it
  370. send_char:    mov leading_zero,0
  371.         call chrout        ;print it
  372.         jmp next_digit
  373. send_space:    mov al,' '        ;pad with spaces
  374.         call chrout
  375. next_digit:    pop ax            ;get remainder back
  376.         sub bp,2        ;point to next lower ten
  377.         jns decout1        ;if still in table, do again
  378.         ret
  379. decout        endp
  380. ;
  381. chrout    proc near
  382.         mov ah,14        ;function call to output
  383.         int video        ;print character
  384.         ret
  385. chrout        endp
  386. ;
  387. routines    proc near        ;misc routines
  388. ;
  389. ;Print message pointed to by DS:DX
  390. ;
  391. print:        push ax
  392.         mov ah,9        ;set function call 9
  393.         int DOS_func        ;print the message
  394.         pop ax
  395.         ret
  396. ;
  397. ;wait for key to be pressed
  398. ;
  399. press_key:    mov ah,0ch        ;function 0ch (clear buffer)
  400.         mov al,7        ;set to no echo, wait for key
  401.         int DOS_func        ;execute
  402.         ret
  403. ;
  404. ;clear the screen
  405. ;
  406. cls:        mov ah,0        ;set 80x25 (clears page)
  407.         mov al,2
  408.         int video
  409.         mov ah,5        ;select page zero
  410.         mov al,0
  411.         int video
  412.         ret            ;return to caller
  413. ;
  414. routines    endp
  415. code        ends
  416.         end
  417. video
  418.         mov ah,5        ;select page zero
  419.         mov al,0